<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html>
<head>
<title>Java games Snake</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="Java, Swing, games, tutorial, 
Snake, programming, GUI, multiplatform">
<meta name="description" content="This part of the Java games tutorial presents the Snake game.">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content">

<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>Snake</h1>


<p>
In this part of the Java 2D games tutorial, we will create a Java Snake game clone. 
</p>

<script type="text/javascript"><!--
google_ad_client = "ca-pub-9706709751191532";
/* LargeSquare */
google_ad_slot = "5070696322";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>


<h2>Snake</h2>

<p>
<b>Snake</b> is an older classic video game. It was first created in late 70s. 
Later it was brought to PCs. In this game the player
controls a snake. The objective is to eat as many apples as possible. Each time 
the snake eats an apple, its body grows. The snake must avoid the walls and its 
own body. This game is sometimes called <b>Nibbles</b>. 
</p>


<h2>Development</h2>

<p>
The size of each of the joints of a snake is 10px. The snake is controlled with the 
cursor keys. Initially the snake has three joints. The game is started by pressing 
one of the cursor keys. If the game is finished, we display Game Over message in 
the middle of the Board. 
</p>

<div class="codehead">Board.java</div>
<pre class="code">
package snake2;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;


public class Board extends JPanel implements ActionListener {

    private final int WIDTH = 300;
    private final int HEIGHT = 300;
    private final int DOT_SIZE = 10;
    private final int ALL_DOTS = 900;
    private final int RAND_POS = 29;
    private final int DELAY = 140;

    private int x[] = new int[ALL_DOTS];
    private int y[] = new int[ALL_DOTS];

    private int dots;
    private int apple_x;
    private int apple_y;

    private boolean left = false;
    private boolean right = true;
    private boolean up = false;
    private boolean down = false;
    private boolean inGame = true;

    private Timer timer;
    private Image ball;
    private Image apple;
    private Image head;


    public Board() {
        addKeyListener(new TAdapter());

        setBackground(Color.black);

        ImageIcon iid = new ImageIcon(this.getClass().getResource("dot.png"));
        ball = iid.getImage();

        ImageIcon iia = new ImageIcon(this.getClass().getResource("apple.png"));
        apple = iia.getImage();

        ImageIcon iih = new ImageIcon(this.getClass().getResource("head.png"));
        head = iih.getImage();

        setFocusable(true);
        initGame();
    }


    public void initGame() {

        dots = 3;

        for (int z = 0; z &lt; dots; z++) {
            x[z] = 50 - z*10;
            y[z] = 50;
        }

        locateApple();

        timer = new Timer(DELAY, this);
        timer.start();
    }


    public void paint(Graphics g) {
        super.paint(g);

        if (inGame) {

            g.drawImage(apple, apple_x, apple_y, this);

            for (int z = 0; z &lt; dots; z++) {
                if (z == 0)
                    g.drawImage(head, x[z], y[z], this);
                else g.drawImage(ball, x[z], y[z], this);
            }

            Toolkit.getDefaultToolkit().sync();
            g.dispose();

        } else {
            gameOver(g);
        }
    }


    public void gameOver(Graphics g) {
        String msg = "Game Over";
        Font small = new Font("Helvetica", Font.BOLD, 14);
        FontMetrics metr = this.getFontMetrics(small);

        g.setColor(Color.white);
        g.setFont(small);
        g.drawString(msg, (WIDTH - metr.stringWidth(msg)) / 2,
                     HEIGHT / 2);
    }


    public void checkApple() {

        if ((x[0] == apple_x) &amp;&amp; (y[0] == apple_y)) {
            dots++;
            locateApple();
        }
    }


    public void move() {

        for (int z = dots; z > 0; z--) {
            x[z] = x[(z - 1)];
            y[z] = y[(z - 1)];
        }

        if (left) {
            x[0] -= DOT_SIZE;
        }

        if (right) {
            x[0] += DOT_SIZE;
        }

        if (up) {
            y[0] -= DOT_SIZE;
        }

        if (down) {
            y[0] += DOT_SIZE;
        }
    }


    public void checkCollision() {

          for (int z = dots; z > 0; z--) {

              if ((z > 4) &amp;&amp; (x[0] == x[z]) &amp;&amp; (y[0] == y[z])) {
                  inGame = false;
              }
          }

        if (y[0] > HEIGHT) {
            inGame = false;
        }

        if (y[0] &lt; 0) {
            inGame = false;
        }

        if (x[0] > WIDTH) {
            inGame = false;
        }

        if (x[0] &lt; 0) {
            inGame = false;
        }
    }

    public void locateApple() {
        int r = (int) (Math.random() * RAND_POS);
        apple_x = ((r * DOT_SIZE));
        r = (int) (Math.random() * RAND_POS);
        apple_y = ((r * DOT_SIZE));
    }

    public void actionPerformed(ActionEvent e) {

        if (inGame) {
            checkApple();
            checkCollision();
            move();
        }

        repaint();
    }


    private class TAdapter extends KeyAdapter {

        public void keyPressed(KeyEvent e) {

            int key = e.getKeyCode();

            if ((key == KeyEvent.VK_LEFT) &amp;&amp; (!right)) {
                left = true;
                up = false;
                down = false;
            }

            if ((key == KeyEvent.VK_RIGHT) &amp;&amp; (!left)) {
                right = true;
                up = false;
                down = false;
            }

            if ((key == KeyEvent.VK_UP) &amp;&amp; (!down)) {
                up = true;
                right = false;
                left = false;
            }

            if ((key == KeyEvent.VK_DOWN) &amp;&amp; (!up)) {
                down = true;
                right = false;
                left = false;
            }
        }
    }
}
</pre>


<p>
First we will define the constants used in our game. 
</p>

<pre class="explanation">
private final int WIDTH = 300;
private final int HEIGHT = 300;
private final int DOT_SIZE = 10;
private final int ALL_DOTS = 900;
private final int RAND_POS = 29;
private final int DELAY = 140;
</pre>

<p>
The WIDTH and HEIGHT constants determine the size of the Board. The DOT_SIZE is the 
size of the apple and the dot of the snake. The ALL_DOTS constant defines the maximum number 
of possible dots on the Board. (900 = 300*300/10*10) The RAND_POS constant is used to calculate 
a random position of an apple. The DELAY constant determines the speed of the game.
</p>

<pre class="explanation">
private int x[] = new int[ALL_DOTS];
private int y[] = new int[ALL_DOTS];
</pre>

<p>
These two arrays store x, y coordinates of all joints of a snake. 
</p>


<p>
In the move() method we have the key algorithm of the game. To understand it, 
look at how the snake is moving. You control 
the head of the snake. You can change its direction with the cursor keys. 
The rest of the joints move one position up the chain. The second joint 
moves where the first was, the third joint where the second was etc. 
</p>

<pre class="explanation">
 for (int z = dots; z > 0; z--) {
     x[z] = x[(z - 1)];
     y[z] = y[(z - 1)];
 }
</pre>

<p>
This code moves the joints up the chain.
</p>

<pre class="explanation">
if (left) {
    x[0] -= DOT_SIZE;
}
</pre>

<p>
Move the head to the left.
</p>

<p>
In the checkCollision() method, we determine if 
the snake has hit itself or one of the walls. 
</p>

<pre class="explanation">
for (int z = dots; z > 0; z--) {

    if ((z > 4) &amp;&amp; (x[0] == x[z]) &amp;&amp; (y[0] == y[z])) {
        inGame = false;
    }
}
</pre>

<p>
Finish the game, if the snake hits one of its joints with the head. 
</p>

<pre class="explanation">
if (y[0] > HEIGHT) {
    inGame = false;
}
</pre>

<p>
Finish the game, if the snake hits the bottom of the Board. 
</p>

<div class="codehead">Snake.java</div>
<pre class="code">
package snake2;

import javax.swing.JFrame;


public class Snake extends JFrame {

    public Snake() {

        add(new Board());

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(320, 340);
        setLocationRelativeTo(null);
        setTitle("Snake");

        setResizable(false);
        setVisible(true);
    }

    public static void main(String[] args) {
        new Snake();
    }
}
</pre>

<p>
This is the main class. 
</p>


<img src="/img/gfx/javagames/snake.png" alt="Snake">
<div class="figure">Figure: Snake</div>


<p>
This was the Snake game. 
</p>

<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div> 
<br>


<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡ 
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified September 26, 2008  <span class="copyright">&copy; 2007 - 2013 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>

